﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using System.Web.Script.Services;
using System.Web.Security;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.Practices.EnterpriseLibrary.Common;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;


namespace TractRecord
{
    public class TractRecordBasePage : Page
    {
        #region Properties

        /// <summary>
        /// A list of external file paths (e.g. javascripts, stylesheets, etc.)
        /// and whether or not those files actually exist.
        /// See the AttachPageSpecificJavaScriptFile() method below for more details.
        /// </summary>
        private Dictionary<string, bool> ExternalFileRegistry
        {
            get
            {
                
                var externalFileRegistry = Application["ExternalFileRegistry"] as Dictionary<string, bool>;
                if (externalFileRegistry == null)
                {
                    externalFileRegistry = new Dictionary<string, bool>();
                    Application["ExternalFileRegistry"] = externalFileRegistry;
                }

                return externalFileRegistry;
            }
        }
        
        /// <summary>
        /// The name of the application, primarily for use by Inf functionality.
        /// </summary>
        protected static string ApplicationName
        {
            get { return "TractRecord.Web"; }
        }

        /// <summary>
        /// The name of the screen/page, primarily for use by Inf functionality.
        /// </summary>
        protected string ScreenName
        {
            get { return Page.GetType().Name.Replace("_aspx", ".aspx"); }
        }

        /// <summary>
        /// An object representing the current user of the applicaton.
        /// </summary>
        public static MembershipUser CurrentUser
        {
            get { return Membership.GetUser(); }
        }

        /// <summary>
        /// The project id.
        /// </summary>
        protected static Guid ProjectId
        {
            get { return HttpContext.Current.Session["ProjectId"] is string ? new Guid(HttpContext.Current.Session["DealId"].ToString()) : Guid.Empty; }
            set { HttpContext.Current.Session["DealId"] = value.ToString(); }
        }

        //protected static LogWriter Logger
        //{
        //    get { return EnterpriseLibraryContainer.Current.GetInstance<LogWriter>(); }
        //}

       #endregion

       #region Constructors

        /// <summary>
        /// Creates a new instance of the class.
        /// </summary>
        public TractRecordBasePage() : base()
        {
            this.Init += new EventHandler(TractRecordBasePage_Init);
            this.Load += new EventHandler(TractRecordBasePage_Load);
            this.PreRender += new EventHandler(TractRecordBasePage_PreRender);
            this.Error += new EventHandler(TractRecordBasePage_Error);
        }

        #endregion


        #region Event Handlers

        /// <summary>
        /// Handles the event that occurs when the page is initializing.
        /// </summary>
        /// <param name="sender">The object that triggered the event.</param>
        /// <param name="e">Information about the event.</param>
        private void TractRecordBasePage_Init(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// Handles the event that occurs when the page is loading.
        /// </summary>
        /// <param name="sender">The object that triggered the event.</param>
        /// <param name="e">Information about the event.</param>
        private void TractRecordBasePage_Load(object sender, EventArgs e)
        {
            if (CurrentUser != null)
            {
                RegisterJavaScriptVariable("userid", CurrentUser.ProviderUserKey.ToString());
            }

            RegisterJavaScriptVariable("displayissuelink", ConfigurationManager.AppSettings["DisplayIssueLink"]);
        }

        /// <summary>
        /// Handles the event that occurs immediately before the page is rendered.
        /// </summary>
        /// <param name="sender">The object that triggered the event.</param>
        /// <param name="e">Information about the event.</param>
        private void TractRecordBasePage_PreRender(object sender, EventArgs e)
        {
            RegisterPageSpecificJavaScriptFile();
            RegisterPageSpecificStyleSheetFile();
        }

        /// <summary>
        /// Handles the event that occurs when an unhandled error occurs.
        /// </summary>
        /// <param name="sender">The object that triggered the event.</param>
        /// <param name="e">Information about the event.</param>
        private void TractRecordBasePage_Error(object sender, EventArgs e)
        {
            // get the exception object that represents the error
            Exception ex = Server.GetLastError();
          
            // log the error
            Code.Common.Log(ex.ToString(), "TractRecordBasePage_Error", 100, 0, System.Diagnostics.TraceEventType.Warning, string.Format(CultureInfo.InvariantCulture, "An unhandled exception has occurred in the web application on {0}.", Server.MachineName)); 
                
            // redirect to a friendly error page
            //Context.Items["InfLogId"] = infLogId;
            Context.Items["Exception"] = ex;
            //Server.Transfer("~/UnhandledError.aspx");
        }

        #endregion


        #region Methods

        /// <summary>
        /// Looks for and attempts to dynamically add a reference in the rendered page
        /// to an external JavaScript file that follows the naming convention {Page}.aspx.js.
        /// See http://blog.jasonbunting.com/PermaLink,guid,5a2506a1-64c6-416d-af16-f33390de54fd.aspx
        /// </summary>
        private void RegisterPageSpecificJavaScriptFile()
        {
            var appRelativeVirtualPath = string.Format(CultureInfo.InvariantCulture, "{0}.js", TemplateControl.AppRelativeVirtualPath);
            if (ExternalFileExists(appRelativeVirtualPath))
            {
                string url = ResolveClientUrl(appRelativeVirtualPath);
                ClientScript.RegisterClientScriptInclude(url, url);
            }
        }

        /// <summary>
        /// Checks if an external file (Javacript, CSS, image, etc.) exists.
        /// </summary>
        /// <param name="appRelativeVirtualPath">The path of the external file to look for</param>
        /// <returns>True if the file exists; otherwise false.</returns>
        protected bool ExternalFileExists(string appRelativeVirtualPath)
        {
            var externalFileRegistry = ExternalFileRegistry;
            if (externalFileRegistry.ContainsKey(appRelativeVirtualPath) == false)
            {
                externalFileRegistry.Add(appRelativeVirtualPath, File.Exists(Server.MapPath(appRelativeVirtualPath)));
            }

            return externalFileRegistry[appRelativeVirtualPath];
        }

        /// <summary>
        /// Dynamically injects JavaScript code into the rendered page to declare a variable.
        /// </summary>
        /// <param name="variableName">The name of the variable.</param>
        /// <param name="variableValue">The value of the variable.</param>
        protected void RegisterJavaScriptVariable(string variableName, object variableValue)
        {
            StringBuilder variableDeclaration = new StringBuilder();
            variableDeclaration.AppendFormat(CultureInfo.InvariantCulture, "var {0} = ", variableName);

            if (variableValue is string || variableValue is char)
            {
                // values that need to be quoted
                variableDeclaration.AppendFormat(CultureInfo.InvariantCulture, "\"{0}\";", variableValue);
            }
            else if (variableValue is int || variableValue is long || variableValue is decimal)
            {
                // values that should not be quoted
                variableDeclaration.AppendFormat(CultureInfo.InvariantCulture, "{0};", variableValue);
            }
            else if (variableValue is bool)
            {
                // need to be lower case true/false
                variableDeclaration.AppendFormat(CultureInfo.InvariantCulture, "{0};", (bool)variableValue ? "true" : "false");
            }
            else if (variableValue is DateTime)
            {
                // date values
                DateTime dt = (DateTime)variableValue;
                variableDeclaration.AppendFormat(CultureInfo.InvariantCulture, "new Date({0}, {1}, {2}, {3}, {4}, {5}, {6});", dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
            }
            else
            {
                // other/object values
                DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(variableValue.GetType());
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    jsonSerializer.WriteObject(memoryStream, variableValue);

                    variableDeclaration.AppendFormat(CultureInfo.InvariantCulture, "{0};", System.Text.Encoding.Default.GetString(memoryStream.ToArray()));
                    memoryStream.Close();
                }
            }

            ClientScript.RegisterStartupScript(this.GetType(), variableName, variableDeclaration.ToString(), true);
        }

        /// <summary>
        /// Looks for and attempts to dynamically add a reference in the rendered page
        /// to an external CSS stylesheet file that follows the naming convention {Page}.aspx.css.
        /// </summary>
        private void RegisterPageSpecificStyleSheetFile()
        {
            var appRelativeVirtualPath = string.Format(CultureInfo.InvariantCulture, "{0}.css", TemplateControl.AppRelativeVirtualPath);
            if (ExternalFileExists(appRelativeVirtualPath))
            {
                string url = ResolveClientUrl(appRelativeVirtualPath);
                string styleSheetLink = string.Format(CultureInfo.InvariantCulture, "<link type=\"text/css\" rel=\"Stylesheet\" href=\"{0}\" />", url);
                Header.Controls.Add(new LiteralControl(styleSheetLink));
            }
        }

        #endregion
    }
}